﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;

namespace AugustVisual
{
    [ToolboxItem(true)]
    [DesignTimeVisible(true)]
    public class AugustDataViewBase : ItemsControl
    {
        public object FocusedObject = null;
        public ColumBase FocusedColumn = null;

        FrameworkElementFactory facVisualizingStackPanel;
       
        public AugustDataViewBase()
        {
            //Style style = (Style)FindResource("dataGridListBoxItem");
            //ItemContainerStyle = style;
            ItemsPanelTemplate itemsPanelTemplate = new ItemsPanelTemplate();
            facVisualizingStackPanel = new FrameworkElementFactory(typeof(AugustVerticleStackPanel));
            facVisualizingStackPanel.SetValue(NameProperty, "VisualizingStackPanel");
            itemsPanelTemplate.VisualTree = facVisualizingStackPanel;
            ItemsPanel = itemsPanelTemplate;
        }

        bool IsInDesignMode => (bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue;
        
  



        public double PresenterWidth
        {
            get { return (double)GetValue(PresenterWidthProperty); }
            set { SetValue(PresenterWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PresenterWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PresenterWidthProperty =
            DependencyProperty.Register("PresenterWidth", typeof(double), typeof(AugustDataViewBase), new FrameworkPropertyMetadata(0d));



        public double PresenterHeight
        {
            get { return (double)GetValue(PresenterHeightProperty); }
            set { SetValue(PresenterHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PresenterHeight.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PresenterHeightProperty =
            DependencyProperty.Register("PresenterHeight", typeof(double), typeof(AugustDataViewBase), new FrameworkPropertyMetadata(0d));



        public Size PresenterSize
        {
            get { return (Size)GetValue(PresenterSizeProperty); }
            set { SetValue(PresenterSizeProperty, value); }
        }

        // Using a DependencyProperty as the backing store for PresenterSize.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PresenterSizeProperty =
            DependencyProperty.Register("PresenterSize", typeof(Size), typeof(AugustDataViewBase), new PropertyMetadata(new Size()));




     

        public string Unit
        {
            get { return (string)GetValue(UnitProperty); }
            set { SetValue(UnitProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Unit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty UnitProperty =
            DependencyProperty.Register("Unit", typeof(string), typeof(AugustDataViewBase), new FrameworkPropertyMetadata(""));

       
    }

    public class ColumnsCollection : ObservableCollection<object>
    {
        IItemsCollection owner;
        public ColumnsCollection()
        {

        }


        public ColumnsCollection(IItemsCollection owner)
        {
            this.owner = owner;
        }
        protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnCollectionChanged(e);
            if (owner != null)
                owner.SetItemsTemplate();
        }
    }


    public interface IItemsCollection
    {
        void OnColumnsPropertyChanged(object oldvalue, object newvalue);
        ColumnsCollection Columns { get; set; }
        void SetItemsTemplate();
    }

    public class AugustDataView : AugustDataViewBase
    {
        static AugustDataView()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(AugustDataView), new FrameworkPropertyMetadata(typeof(AugustDataView)));
        }
        public event NotifyCollectionChangedEventHandler NotifyCollectionChanged;
        public AugustDataView()
        {
            Loaded += AugustDataView_Loaded;
            Columns = new ColumnsCollection();
        }

        public ColumnsCollection Columns
        {
            get
            { return (ColumnsCollection)GetValue(ColumnsProperty); }
            set { SetValue(ColumnsProperty, value); }
        }

        public static readonly DependencyProperty ColumnsProperty =
            DependencyProperty.Register("Columns", typeof(ColumnsCollection), typeof(AugustDataView), new FrameworkPropertyMetadata(null));


        public Brush HeaderRowBackColor
        {
            get { return (Brush)GetValue(HeaderRowBackColorProperty); }
            set { SetValue(HeaderRowBackColorProperty, value); }
        }

        // Using a DependencyProperty as the backing store for DataColumnRowBackColor.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderRowBackColorProperty =
            DependencyProperty.Register(nameof(HeaderRowBackColor), typeof(Brush), typeof(AugustDataViewBase), new FrameworkPropertyMetadata(new SolidColorBrush(Color.FromArgb(100, 99, 99, 99))));


        public double HeaderRowHeight
        {
            get { return (double)GetValue(HeaderRowHeightProperty); }
            set { SetValue(HeaderRowHeightProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Height.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderRowHeightProperty =
            DependencyProperty.Register(nameof(HeaderRowHeight), typeof(double), typeof(AugustDataViewBase), new FrameworkPropertyMetadata(30d));
        private void AugustDataView_Loaded(object sender, RoutedEventArgs e)
        {
            if (!FrameworkElementHelper.IsInDesignMode)
            {
                if (scrollViewerBarBinding == null)
                {
                    DependencyObject dependencyObject = FrameworkElementHelper.Findchild(this, "bodyscroll");
                    if (dependencyObject is ScrollViewerBarBinding)
                    {
                        scrollViewerBarBinding = (ScrollViewerBarBinding)dependencyObject;
                        scrollViewerBarBinding.ScrollChanged += ScrollViewerBarBinding_ScrollChanged;
                    }
                }
                if (headerColumnRow == null)
                {
                    headerColumnRow = (HeaderColumnRow)FrameworkElementHelper.Findchild(this, "headerColumnRow");
                    if (headerColumnRow != null)
                    {
                        headerColumnRow.ChildHeaderColumnCellChanged += HeaderColumnRow_ChildHeaderColumnCellChanged;
                    }
                }
            }
        }

        private void HeaderColumnRow_ChildHeaderColumnCellChanged(object sender, EventArgs e)
        {
            childHeaderColumnCells = headerColumnRow.ChildHeaderColumnCells;
            for (int k = 0; k < childHeaderColumnCells.Length; k++)
            {
                ((HeaderColumnCell)childHeaderColumnCells[k]).HeaderColumnCellMouseDown += AugustDataView_HeaderColumnCellMouseDown;
            }
        }

        private void ScrollViewerBarBinding_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            if (e.HorizontalChange != 0)
            {
                headerColumnRow.Margin = new Thickness(-e.HorizontalOffset, headerColumnRow.Margin.Top, headerColumnRow.Margin.Right, headerColumnRow.Margin.Bottom);
            }
        }

        public object BindingTest
        {
            get { return (object)GetValue(BindingTestProperty); }
            set { SetValue(BindingTestProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BindingTest.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BindingTestProperty =
            DependencyProperty.Register("BindingTest", typeof(object), typeof(AugustDataView), new PropertyMetadata(null));


        private HeaderColumnRow headerColumnRow = null;
        ScrollViewerBarBinding scrollViewerBarBinding = null;
        FrameworkElement[] childHeaderColumnCells;



        public new IEnumerable ItemsSource
        {
            get
            {
                return itemsSourceNormal;
            }
            set
            {
                NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset);
                itemsSourceNormal = (IEnumerable<object>)value;
                base.ItemsSource = itemsSourceNormal;
                OriginSourceChanged(itemsSourceNormal, notifyCollectionChangedEventArgs);
                EventInfo eventInfo = itemsSourceNormal.GetType().GetEvent("CollectionChanged");
                if (eventInfo != null)
                {
                    eventInfo.AddEventHandler(itemsSourceNormal, new NotifyCollectionChangedEventHandler(OriginSourceChanged));
                }
            }
        }

        protected virtual void OriginSourceChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            NotifyCollectionChanged?.Invoke(this, e);
            if (sortState != 0)
            {
                AugustDataView_HeaderColumnCellMouseDown(null, dispbinding, sortState);
            }
            if (scrollViewerBarBinding == null)
            {
                DependencyObject dependencyObject = FrameworkElementHelper.Findchild(this, "bodyscroll");
                if (dependencyObject is ScrollViewerBarBinding)
                {
                    scrollViewerBarBinding = (ScrollViewerBarBinding)dependencyObject;
                }
            }
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                if (scrollStyle != DataGridScrollStyle.None)
                {
                    ApplyScrollStyle();
                }
            }
        }

        IEnumerable<object> itemsSourceNormal;
        IEnumerable<object> itemsSourceDESC;
        IEnumerable<object> itemsSourceASC;

        Binding dispbinding = null;
        int sortState;
        private void AugustDataView_HeaderColumnCellMouseDown(HeaderColumnCell headerColumnCell, Binding dispBinding, int sortState)
        {
            if (itemsSourceNormal == null || itemsSourceNormal.Count() == 0) return;

            dispbinding = dispBinding;
            this.sortState = sortState;
            if (sortState == 1)
            {
                UIElementCollection uIElementCollection = scrollViewerBarBinding.stackPanel.InternalChildren;
                UIElement[] contentControls = new UIElement[uIElementCollection.Count];
                for (int i = 0; i < contentControls.Length; i++)
                {
                    contentControls[i] = uIElementCollection[i];
                }
                itemsSourceASC = itemsSourceNormal.OrderBy(Orderfunc);
                base.ItemsSource = itemsSourceASC;
                scrollViewerBarBinding.ReUseAllContainer(contentControls);

                scrollViewerBarBinding.SetOffset(scrollViewerBarBinding.scrollNum);

            }
            else if (sortState == 2)
            {
                UIElementCollection uIElementCollection = scrollViewerBarBinding.stackPanel.InternalChildren;
                UIElement[] contentControls = new UIElement[uIElementCollection.Count];
                for (int i = 0; i < contentControls.Length; i++)
                {
                    contentControls[i] = uIElementCollection[i];
                }
                itemsSourceDESC = itemsSourceNormal.OrderByDescending(Orderfunc);
                base.ItemsSource = itemsSourceDESC;
                scrollViewerBarBinding.ReUseAllContainer(contentControls);
                scrollViewerBarBinding.SetOffset(scrollViewerBarBinding.scrollNum);
            }
            else
            {
                if (headerColumnCell != null)
                {
                    base.ItemsSource = itemsSourceNormal;
                    scrollViewerBarBinding.RealizeAllContainer();
                    scrollViewerBarBinding.SetOffset(scrollViewerBarBinding.scrollNum);
                }
            }
        }

        private object Orderfunc(object userInfo)
        {
            return userInfo.GetType().GetProperty(dispbinding.Path.Path).GetValue(userInfo);
        }



        private DataGridScrollStyle scrollStyle = DataGridScrollStyle.None;

        public DataGridScrollStyle ScrollStyle
        {
            get { return scrollStyle; }
            set { scrollStyle = value; }
        }

        private void ApplyScrollStyle()
        {
            if (this.scrollViewerBarBinding == null) return;
            ScrollViewerBarBinding scrollViewerBarBinding = this.scrollViewerBarBinding;
            DataGridScrollStyle dataGridScrollStyle = scrollStyle;
            switch (dataGridScrollStyle)
            {
                case DataGridScrollStyle.None:
                    break;
                case DataGridScrollStyle.ScrollToBottom:
                    scrollViewerBarBinding.ScrollToBottom();
                    break;
                case DataGridScrollStyle.ScrollToEnd:
                    scrollViewerBarBinding.ScrollToEnd();
                    break;
                case DataGridScrollStyle.ScrollToHome:
                    scrollViewerBarBinding.ScrollToHome();
                    break;
                case DataGridScrollStyle.ScrollToLeftEnd:
                    scrollViewerBarBinding.ScrollToLeftEnd();
                    break;
                case DataGridScrollStyle.ScrollToRightEnd:
                    scrollViewerBarBinding.ScrollToRightEnd();
                    break;
                case DataGridScrollStyle.ScrollToTop:
                    scrollViewerBarBinding.ScrollToTop();
                    break;
            }
        }
    }

    public class ColumBase : DependencyObject,INotifyPropertyChanged
    {

        public Brush BackGround
        {
            get { return (Brush)GetValue(BackGroundProperty); }
            set { SetValue(BackGroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BackGroundProperty =
            DependencyProperty.Register("BackGround", typeof(Brush), typeof(ColumBase), new FrameworkPropertyMetadata(Panel.BackgroundProperty.DefaultMetadata.DefaultValue, FrameworkPropertyMetadataOptions.None));
        public string Header
        {
            get { return (string)GetValue(HeaderProperty); }
            set { SetValue(HeaderProperty, value); }
        }
        // Using a DependencyProperty as the backing store for Header.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HeaderProperty =
            DependencyProperty.Register("Header", typeof(string), typeof(ColumBase), new FrameworkPropertyMetadata("Header"));

        public double Width
        {
            get { return (double)GetValue(WidthProperty); }
            set { SetValue(WidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Width.  This enables animation, styling, binding, etc...
        public static  readonly DependencyProperty WidthProperty =
            DependencyProperty.Register("Width", typeof(double), typeof(ColumBase), new FrameworkPropertyMetadata(100d));

        private Binding _displayMemberBinding;

        public event PropertyChangedEventHandler PropertyChanged;

        public Binding DisplayMemberBinding
        {
            get
            {
                return _displayMemberBinding;
            }
            set
            {
                if (_displayMemberBinding != value)
                {
                    _displayMemberBinding = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DisplayMemberBinding"));
                }
            }
        }
    }

    public class Column : ColumBase
    {

        public Column() : base()
        {

        }


    }
}
